using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp;
using Volo.Abp.Domain.Services;
using Volo.Abp.Identity;
using Volo.Abp.Domain.Entities;
using UserManagementService.Users;

namespace UserManagementService.Organizations;

/// <summary>
/// 组织管理服务实现
/// </summary>
public class OrganizationManagementService : DomainService, IOrganizationManagementService
{
    private readonly IOrganizationRepository _organizationRepository;
    private readonly IIdentityUserRepository _userRepository;
    private readonly ILogger<OrganizationManagementService> _logger;

    public OrganizationManagementService(
        IOrganizationRepository organizationRepository,
        IIdentityUserRepository userRepository,
        ILogger<OrganizationManagementService> logger)
    {
        _organizationRepository = organizationRepository;
        _userRepository = userRepository;
        _logger = logger;
    }

    public async Task<Organization> CreateAsync(
        string code,
        string name,
        OrganizationType type,
        Guid? parentId = null,
        string? description = null,
        Guid? tenantId = null,
        CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("创建组织: Code={Code}, Name={Name}, Type={Type}, ParentId={ParentId}",
            code, name, type, parentId);

        // 检查编码是否可用
        if (!await IsCodeAvailableAsync(code, null, tenantId, cancellationToken))
        {
            throw new BusinessException($"组织编码 '{code}' 已存在");
        }

        // 验证父组织
        if (parentId.HasValue)
        {
            var parentOrganization = await _organizationRepository.GetAsync(parentId.Value, cancellationToken: cancellationToken);
            if (parentOrganization == null)
            {
                throw new EntityNotFoundException(typeof(Organization), parentId.Value);
            }
        }

        var organization = new Organization(
            Guid.NewGuid(),
            tenantId,
            code,
            name,
            type,
            parentId,
            description
        );

        return await _organizationRepository.InsertAsync(organization, true, cancellationToken);
    }

    public async Task<Organization> UpdateAsync(
        Guid id,
        string name,
        string? description = null,
        CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("更新组织: Id={Id}, Name={Name}", id, name);

        var organization = await _organizationRepository.GetAsync(id, cancellationToken: cancellationToken);
        if (organization == null)
        {
            throw new EntityNotFoundException(typeof(Organization), id);
        }

        organization.UpdateInfo(name, description);

        return await _organizationRepository.UpdateAsync(organization, true, cancellationToken);
    }

    public async Task DeleteAsync(Guid id, bool force = false, CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("删除组织: Id={Id}, Force={Force}", id, force);

        var organization = await _organizationRepository.GetAsync(id, cancellationToken: cancellationToken);
        if (organization == null)
        {
            throw new EntityNotFoundException(typeof(Organization), id);
        }

        // 检查是否有子组织
        var childOrganizations = await _organizationRepository.GetChildrenAsync(id, cancellationToken: cancellationToken);
        if (childOrganizations.Any() && !force)
        {
            throw new BusinessException("存在子组织，无法删除。请先删除所有子组织或使用强制删除。");
        }

        // 检查是否有成员
        var members = await _organizationRepository.GetMembersAsync(id, cancellationToken: cancellationToken);
        if (members.Any() && !force)
        {
            throw new BusinessException("存在组织成员，无法删除。请先移除所有成员或使用强制删除。");
        }

        await _organizationRepository.DeleteAsync(organization, true, cancellationToken);
    }

    public async Task<Organization> MoveAsync(
        Guid id,
        Guid? newParentId,
        CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("移动组织: Id={Id}, NewParentId={NewParentId}", id, newParentId);

        var organization = await _organizationRepository.GetAsync(id, cancellationToken: cancellationToken);
        if (organization == null)
        {
            throw new EntityNotFoundException(typeof(Organization), id);
        }

        // 验证新父组织
        if (newParentId.HasValue)
        {
            if (newParentId.Value == id)
            {
                throw new BusinessException("不能将组织移动到自己下面");
            }

            var parentOrganization = await _organizationRepository.GetAsync(newParentId.Value, cancellationToken: cancellationToken);
            if (parentOrganization == null)
            {
                throw new EntityNotFoundException(typeof(Organization), newParentId.Value);
            }

            // 检查是否会形成循环
            if (await WouldCreateCycleAsync(id, newParentId.Value, cancellationToken))
            {
                throw new BusinessException("移动后会导致组织层级循环，无法移动");
            }
        }

        await _organizationRepository.MoveOrganizationAsync(id, newParentId, cancellationToken);
        organization.SetParent(newParentId);

        return await _organizationRepository.UpdateAsync(organization, true, cancellationToken);
    }

    public async Task<Organization> EnableAsync(Guid id, CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("启用组织: Id={Id}", id);

        var organization = await _organizationRepository.GetAsync(id, cancellationToken: cancellationToken);
        if (organization == null)
        {
            throw new EntityNotFoundException(typeof(Organization), id);
        }

        organization.Enable();

        return await _organizationRepository.UpdateAsync(organization, true, cancellationToken);
    }

    public async Task<Organization> DisableAsync(Guid id, CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("禁用组织: Id={Id}", id);

        var organization = await _organizationRepository.GetAsync(id, cancellationToken: cancellationToken);
        if (organization == null)
        {
            throw new EntityNotFoundException(typeof(Organization), id);
        }

        organization.Disable();

        return await _organizationRepository.UpdateAsync(organization, true, cancellationToken);
    }

    public async Task<OrganizationMember> AddMemberAsync(
        Guid organizationId,
        Guid userId,
        string? position = null,
        string? description = null,
        bool isManager = false,
        CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("添加组织成员: OrganizationId={OrganizationId}, UserId={UserId}, Position={Position}",
            organizationId, userId, position);

        var organization = await _organizationRepository.GetAsync(organizationId, cancellationToken: cancellationToken);
        if (organization == null)
        {
            throw new EntityNotFoundException(typeof(Organization), organizationId);
        }

        var user = await _userRepository.GetAsync(userId, cancellationToken: cancellationToken);
        if (user == null)
        {
            throw new EntityNotFoundException(typeof(IdentityUser), userId);
        }

        // 检查用户是否已经是成员
        var existingMembers = await _organizationRepository.GetMembersAsync(organizationId, cancellationToken: cancellationToken);
        if (existingMembers.Any(m => m.UserId == userId))
        {
            throw new BusinessException("用户已经是该组织的成员");
        }

        var member = new OrganizationMember(
            GuidGenerator.Create(),
            organizationId,
            userId,
            position,
            description
        );

        if (isManager)
        {
            member.SetManager(true);
        }

        organization.Members.Add(member);
        await _organizationRepository.UpdateAsync(organization, true, cancellationToken);
        return member;
    }

    public async Task RemoveMemberAsync(
        Guid organizationId,
        Guid userId,
        CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("移除组织成员: OrganizationId={OrganizationId}, UserId={UserId}",
            organizationId, userId);

        var organization = await _organizationRepository.GetAsync(organizationId, cancellationToken: cancellationToken);
        if (organization == null)
        {
            throw new EntityNotFoundException(typeof(Organization), organizationId);
        }

        organization.RemoveMember(userId);

        await _organizationRepository.UpdateAsync(organization, true, cancellationToken);
    }

    public async Task<OrganizationMember> UpdateMemberAsync(
        Guid organizationId,
        Guid userId,
        string? position = null,
        string? description = null,
        bool? isManager = null,
        CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("更新组织成员: OrganizationId={OrganizationId}, UserId={UserId}",
            organizationId, userId);

        var organization = await _organizationRepository.GetAsync(organizationId, cancellationToken: cancellationToken);
        if (organization == null)
        {
            throw new EntityNotFoundException(typeof(Organization), organizationId);
        }

        var member = organization.Members.FirstOrDefault(m => m.UserId == userId);
        if (member == null)
        {
            throw new EntityNotFoundException("用户不是该组织的成员");
        }

        member.UpdateInfo(position, description);

        if (isManager.HasValue)
        {
            member.SetManager(isManager.Value);
        }

        await _organizationRepository.UpdateAsync(organization, true, cancellationToken);
        return member;
    }

    public async Task<List<OrganizationMember>> GetMembersAsync(
        Guid organizationId,
        bool includeInactive = false,
        CancellationToken cancellationToken = default)
    {
        var members = await _organizationRepository.GetMembersAsync(organizationId, true, cancellationToken);

        if (!includeInactive)
        {
            members = members.Where(m => m.IsActive).ToList();
        }

        return members;
    }

    public async Task<List<Organization>> GetUserOrganizationsAsync(
        Guid userId,
        bool includeInactive = false,
        CancellationToken cancellationToken = default)
    {
        return await _organizationRepository.GetUserOrganizationsAsync(userId, includeInactive, cancellationToken);
    }

    public async Task<List<Organization>> GetOrganizationTreeAsync(
        Guid? rootId = null,
        int maxDepth = 10,
        CancellationToken cancellationToken = default)
    {
        return await _organizationRepository.GetOrganizationTreeAsync(rootId, true, cancellationToken);
    }

    public async Task<bool> IsCodeAvailableAsync(
        string code,
        Guid? excludeId = null,
        Guid? tenantId = null,
        CancellationToken cancellationToken = default)
    {
        return !await _organizationRepository.IsCodeExistAsync(code, excludeId, cancellationToken);
    }

    public async Task<OrganizationImportResult> ImportOrganizationsAsync(
        List<OrganizationImportDto> organizations,
        Guid? tenantId = null,
        CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("批量导入组织: Count={Count}, TenantId={TenantId}",
            organizations.Count, tenantId);

        var result = new OrganizationImportResult
        {
            TotalCount = organizations.Count
        };

        foreach (var orgDto in organizations)
        {
            try
            {
                var parentId = (Guid?)null;
                if (!string.IsNullOrEmpty(orgDto.ParentCode))
                {
                    var parentOrg = await _organizationRepository.GetByCodeAsync(orgDto.ParentCode, cancellationToken: cancellationToken);
                    parentId = parentOrg?.Id;
                }

                await CreateAsync(
                    orgDto.Code,
                    orgDto.Name,
                    orgDto.Type,
                    parentId,
                    orgDto.Description,
                    tenantId,
                    cancellationToken
                );

                result.SuccessCount++;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "导入组织失败: Code={Code}, Error={Error}", orgDto.Code, ex.Message);
                result.FailureCount++;
                result.ErrorMessages.Add($"组织 {orgDto.Code} 导入失败: {ex.Message}");
            }
        }

        return result;
    }

    public async Task<List<OrganizationExportDto>> ExportOrganizationsAsync(
        Guid? rootId = null,
        bool includeMembers = false,
        CancellationToken cancellationToken = default)
    {
        var organizations = await GetOrganizationTreeAsync(rootId, cancellationToken: cancellationToken);
        var exportDtos = new List<OrganizationExportDto>();

        foreach (var org in organizations)
        {
            var members = includeMembers ? await GetMembersAsync(org.Id, cancellationToken: cancellationToken) : new List<OrganizationMember>();

            var exportDto = new OrganizationExportDto
            {
                Id = org.Id,
                Code = org.Code,
                Name = org.Name,
                Type = org.Type,
                ParentCode = org.ParentId.HasValue ? organizations.FirstOrDefault(o => o.Id == org.ParentId.Value)?.Code : null,
                Description = org.Description,
                IsEnabled = org.IsEnabled,
                CreationTime = org.CreationTime,
                MemberCount = members.Count,
                MemberNames = members.Select(m => m.UserId.ToString()).ToList()
            };

            exportDtos.Add(exportDto);
        }

        return exportDtos;
    }

    public async Task SyncOrganizationStructureAsync(
        Guid organizationId,
        CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("同步组织结构: OrganizationId={OrganizationId}", organizationId);

        var organization = await _organizationRepository.GetAsync(organizationId, cancellationToken: cancellationToken);
        if (organization == null)
        {
            throw new EntityNotFoundException(typeof(Organization), organizationId);
        }

        // TODO: 实现组织结构同步逻辑
        // 可以是与外部系统的数据同步，如LDAP、AD等
    }

    private async Task<bool> WouldCreateCycleAsync(
        Guid organizationId,
        Guid newParentId,
        CancellationToken cancellationToken = default)
    {
        // 检查移动后是否会造成循环引用
        var currentParent = await _organizationRepository.GetAsync(newParentId, cancellationToken: cancellationToken);

        while (currentParent != null)
        {
            if (currentParent.Id == organizationId)
            {
                return true; // 会形成循环
            }

            if (currentParent.ParentId.HasValue)
            {
                currentParent = await _organizationRepository.GetAsync(currentParent.ParentId.Value, cancellationToken: cancellationToken);
            }
            else
            {
                break;
            }
        }

        return false;
    }
}